package com.baijiayun.live.ui.chat

import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.baijiahulian.common.networkv2.BJProgressCallback
import com.baijiahulian.common.networkv2.BJResponse
import com.baijiahulian.common.networkv2.HttpException
import com.baijiayun.live.ui.R
import com.baijiayun.live.ui.base.BaseViewModel
import com.baijiayun.live.ui.base.RouterViewModel
import com.baijiayun.live.ui.chat.widget.ChatMessageView
import com.baijiayun.live.ui.isAdmin
import com.baijiayun.livecore.context.LPConstants
import com.baijiayun.livecore.models.*
import com.baijiayun.livecore.models.imodels.IMessageModel
import com.baijiayun.livecore.utils.LPChatMessageParser
import com.baijiayun.livecore.utils.LPJsonUtils
import com.baijiayun.livecore.utils.LPLogger
import com.baijiayun.liveuibase.utils.ToastUtil
import com.google.gson.JsonObject
import io.reactivex.android.schedulers.AndroidSchedulers
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.LinkedBlockingQueue

/**
 * Created by yongjiaming on 2019-10-28
 * Describe:
 */
class ChatViewModel(val routerViewModel: RouterViewModel) : BaseViewModel() {

    var redPointNumber = MutableLiveData<Int>()
    val notifyItemChange = MutableLiveData<Int>()
    val notifyItemInsert = MutableLiveData<Int>()
    val notifyDataSetChange = MutableLiveData<Unit>()
    val notifyStickyMessage = MutableLiveData<List<IMessageModel>>()
    val notifyLoadDataComplete = MutableLiveData<Unit>()

    // 表情 字典
    val expressions = HashMap<String, String>()

    // 不是自己发送的消息
    var receivedNewMsgNum = 0
    var isSelfForbidden: Boolean = false

    // 过滤只看老师
    var filterMessage = false
    var forbidPrivateChat = false

    // 0默认没收到消息1，收到自己的 2，收到其他人的
    var receiveMsgType = MsgType.None

    // 抽奖中
    var isLotterying = false
    val notifyLotteryEnd = MutableLiveData<Unit>()
    val notifyForbidChat = MutableLiveData<Boolean>()

    // 数据源同步，不从ChatVM取getMessage()和getMessageCount()
    private val messageList = LinkedHashSet<IMessageModel>()

    val onlineUserGroup = MutableLiveData<List<LPGroupItem>>()


    enum class MsgType {
        None, Me, Other
    }

    private val liveRoom by lazy {
        routerViewModel.liveRoom
    }

    private val imageMessageUploadingQueue by lazy {
        LinkedBlockingQueue<UploadingImageModel>()
    }

    private val translateMessageModels by lazy {
        ConcurrentHashMap<String, LPMessageTranslateModel>()
    }

    // 私聊消息
    private val privateChatMessagePool by lazy {
        ConcurrentHashMap<String, ArrayList<IMessageModel>>()
    }

    // 私聊消息分页，当前请求所在页数，每个私聊对象对应的页数
    private val privateChatMessagePageMap by lazy {
        HashMap<String, Int>()
    }

    // 私聊消息分页，key->user_num,value->hasmore
    private val privateChatMessagePageHasMoreMap by lazy {
        HashMap<String, Boolean>()
    }

    // 私聊消息，过滤只看老师和主讲
    private val privateChatMessageFilterList by lazy {
        ArrayList<IMessageModel>()
    }

    // 公聊消息，过滤只看老师和主讲
    private val chatMessageFilterList by lazy {
        ArrayList<IMessageModel>()
    }

    override fun subscribe() {
        for (lpExpressionModel in liveRoom.chatVM.expressions) {
            expressions["[" + lpExpressionModel.name + "]"] = lpExpressionModel.url
            expressions["[" + lpExpressionModel.key + "]"] = lpExpressionModel.url
            expressions["[" + lpExpressionModel.nameEn + "]"] = lpExpressionModel.url
        }
        chatMessageFilterList.clear()
        chatMessageFilterList.addAll(getFilterMessageList(liveRoom.chatVM.messageList))
        messageList.clear()
        messageList.addAll(liveRoom.chatVM.messageList)
        compositeDisposable.add(liveRoom.chatVM
            .observableOfNotifyDataChange
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                chatMessageFilterList.clear()
                chatMessageFilterList.addAll(getFilterMessageList(it))
                messageList.clear()
                messageList.addAll(it)
                notifyDataSetChange.value = Unit
            })

        compositeDisposable.add(liveRoom.chatVM
            .observableOfReceiveMessage
            .onBackpressureBuffer()
            .doOnNext {
                if (it.from.userId != liveRoom.currentUser.userId) {
                    receiveMsgType = MsgType.Other
                    receivedNewMsgNum = receivedNewMsgNum.plus(1)
                    val redPointCount = redPointNumber.value
                    if (routerViewModel.action2Chat.value == true) {
                        redPointNumber.value = 0
                    } else {
                        redPointNumber.value = if (redPointCount == null) 1 else redPointCount + 1
                    }
                } else {
                    receiveMsgType = MsgType.Me
                    if (isLotterying) {
                        val commandLotteryModel = routerViewModel.actionCommandLotteryStart.value
                        if (it.content == commandLotteryModel?.command) {
                            isLotterying = false
                            notifyLotteryEnd.value = Unit
                            liveRoom.toolBoxVM.requestCommandLottery(liveRoom.currentUser.number)
                        }
                    }
                }
                if (it.isPrivateChat && it.toUser != null) {
                    val userNumber = if (it.from.number == liveRoom.currentUser.number) {
                        it.toUser.number
                    } else {
                        it.from.number
                    }
                    var tempMessageList: MutableList<IMessageModel>? =
                        privateChatMessagePool[userNumber]
                    if (tempMessageList == null) {
                        tempMessageList = ArrayList()
                        privateChatMessagePool[userNumber] = tempMessageList
                    }
                    tempMessageList.add(it)
                    if (isPrivateChatMode()) {
                        privateChatMessageFilterList.clear()
                        privateChatMessageFilterList.addAll(
                            getFilterMessageList(
                                privateChatMessagePool[routerViewModel.privateChatUser.value!!.number]
                            )
                        )
                    }
                }
            }
            .filter {
                val filter = when {
                    isPrivateChatMode() -> true
                    "-1" == it.to -> false
                    it.toUser == null -> false
                    else -> {
                        val privateChatUser = routerViewModel.privateChatUser.value
                        if (privateChatUser == null) true else privateChatUser.number == it.toUser.number || privateChatUser.number == it.from.number
                    }
                }
                filter
            }
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                messageList.add(it)
                if (it.messageType == LPConstants.MessageType.Image && it.from.userId == liveRoom.currentUser.userId) {
                    notifyItemChange.value = getCount() - imageMessageUploadingQueue.size - 1
                }
                notifyItemInsert.value = getCount() - 1
            })
        compositeDisposable.add(liveRoom.chatVM
            .observableOfReceiveTranslateMessage
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                translateMessageModels[it.messageId] = it
                notifyDataSetChange.value = Unit
            }
        )
        compositeDisposable.add(liveRoom.chatVM.observableOfMsgStickyList
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                if (it != null) {
                    notifyStickyMessage.value = it
                    notifyDataSetChange.value = Unit
                }
            })
        compositeDisposable.add(liveRoom.chatVM.observableOfMsgRevoke
            .observeOn(AndroidSchedulers.mainThread())
            .filter { it.messageId != null }
            .subscribe { lpMessageRevoke ->
                translateMessageModels.remove(lpMessageRevoke.messageId)
                if (lpMessageRevoke.fromId != liveRoom.currentUser.userId) {
                    receivedNewMsgNum = receivedNewMsgNum.minus(1)
                }
                for (iMessageModel in imageMessageUploadingQueue) {
                    if (lpMessageRevoke.messageId == iMessageModel.id) {
                        imageMessageUploadingQueue.remove(iMessageModel)
                        break
                    }
                }
                for (iMessageModel in privateChatMessageFilterList) {
                    if (lpMessageRevoke.messageId == iMessageModel.id) {
                        privateChatMessageFilterList.remove(iMessageModel)
                        break
                    }
                }
                for (iMessageModel in chatMessageFilterList) {
                    if (lpMessageRevoke.messageId == iMessageModel.id) {
                        chatMessageFilterList.remove(iMessageModel)
                        break
                    }
                }
                val topList = notifyStickyMessage.value?.toMutableList()
                if (topList != null) {
                    for (message in topList) {
                        if (message.id == lpMessageRevoke.messageId) {
                            topList -= message
                            stickyMessage(topList)
                            break
                        }
                    }
                }
                if (isPrivateChatMode()) {
                    val iMessageModels =
                        privateChatMessagePool[routerViewModel.privateChatUser.value!!.number]
                    if (iMessageModels != null) {
                        for (iMessageModel in iMessageModels) {
                            if (lpMessageRevoke.messageId == iMessageModel.id) {
                                iMessageModels.remove(iMessageModel)
                                break
                            }
                        }
                    }
                } else {
                    // 接收消息端（to），key为from.name
                    // 发送消息端（from）,key为to.name
                    for (key in privateChatMessagePool.keys) {
                        val iMessageModels = privateChatMessagePool[key]
                        if (iMessageModels != null) {
                            for (iMessageModel in iMessageModels) {
                                if (lpMessageRevoke.messageId == iMessageModel.id) {
                                    iMessageModels.remove(iMessageModel)
                                    break
                                }
                            }
                        }
                    }
                }
                notifyDataSetChange.value = Unit
            }
        )
        compositeDisposable.add(liveRoom.observableOfIsSelfChatForbid
            .observeOn(AndroidSchedulers.mainThread())
            .filter { !isAdmin(liveRoom) }
            .subscribe {
                isSelfForbidden = it
                notifyForbidChat.value = liveRoom.forbidAllChatStatus || isSelfForbidden
            })
        compositeDisposable.add(liveRoom.observableOfForbidAllChatStatus
            .observeOn(AndroidSchedulers.mainThread())
            .filter { !isAdmin(liveRoom) }
            .subscribe {
                notifyForbidChat.value = liveRoom.forbidAllChatStatus || isSelfForbidden
            })
        compositeDisposable.add(liveRoom.chatVM.observableOfWhisperList
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                var tempMessageList: MutableList<IMessageModel>? =
                    privateChatMessagePool[it.to]
                if (tempMessageList == null) {
                    tempMessageList = ArrayList()
                    privateChatMessagePool[it.to] = tempMessageList as ArrayList<IMessageModel>
                }
                privateChatMessagePageHasMoreMap[it.to] = it.hasMore
                if (it.hasMore && privateChatMessagePageMap[it.to] != null) {
                    privateChatMessagePageMap[it.to] = privateChatMessagePageMap[it.to]!! + 1
                }
                tempMessageList!!.addAll(0, it.whisperList.reversed())
                if (isPrivateChatMode()) {
                    notifyDataSetChange.value = Unit
                }
            })
        compositeDisposable.add(liveRoom.onlineUserVM.observableOfOnGroupItem
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                onlineUserGroup.value = it
            })
        liveRoom.onlineUserVM.requestGroupInfoReq()
        liveRoom.requestAnnouncement(true)
    }

    fun isPrivateChatMode() = routerViewModel.privateChatUser.value != null

    fun canWhisperTeacherInForbidAllMode(): Boolean {
        return if (isAdmin(liveRoom)) {
            true
        } else liveRoom.partnerConfig.canWisperTeacherInForbidAllMode == 1
    }

    fun getCount(): Int {
        return if (isPrivateChatMode()) {
            var list = privateChatMessagePool[routerViewModel.privateChatUser.value!!.number]
            if (filterMessage) {
                list = privateChatMessageFilterList
            }
            if (list == null) 0 else list.size + imageMessageUploadingQueue.size
        } else {
            if (filterMessage) {
                chatMessageFilterList.size + imageMessageUploadingQueue.size
            } else messageList.size + imageMessageUploadingQueue.size
        }
    }

    fun getMessage(position: Int): IMessageModel {
        if (isPrivateChatMode()) {
            var list = privateChatMessagePool[routerViewModel.privateChatUser.value!!.getNumber()]
            if (filterMessage) {
                list = privateChatMessageFilterList
            }
            val messageCount = list?.size ?: 0
            return if (position < messageCount) {
                list!![position]
            } else {
                imageMessageUploadingQueue.toTypedArray()[position - messageCount]
            }
        } else {
            var messageCount = messageList.size
            if (filterMessage) {
                messageCount = chatMessageFilterList.size
            }
            return if (position < messageCount) {
                if (filterMessage) {
                    chatMessageFilterList[position]
                } else {
                    messageList.elementAt(position)
                }
            } else {
                imageMessageUploadingQueue.toTypedArray()[position - messageCount]
            }
        }
    }

    fun sendImageMessage(path: String) {
        val model = UploadingImageModel(path, liveRoom.currentUser, null)
        imageMessageUploadingQueue.offer(model)
        notifyDataSetChange.value = Unit
        continueUploadQueue()
    }

    fun continueUploadQueue() {
        val model = imageMessageUploadingQueue.peek() ?: return
        liveRoom.chatVM.uploadImageWithProgress(model.url, this, object : BJProgressCallback() {
            override fun onProgress(l: Long, l1: Long) {
                LPLogger.d("$l/$l1")
            }

            override fun onFailure(e: HttpException) {
                model.status = UploadingImageModel.STATUS_UPLOAD_FAILED
                notifyDataSetChange.postValue(Unit)
            }

            override fun onResponse(bjResponse: BJResponse) {
                val shortResult: LPShortResult<*>
                try {
                    shortResult = LPJsonUtils.parseString(
                        bjResponse.response.body()!!.string(),
                        LPShortResult::class.java
                    )
                    val uploadModel = LPJsonUtils.parseJsonObject(
                        shortResult.data as JsonObject,
                        LPUploadDocModel::class.java
                    )
                    val imageContent = LPChatMessageParser.toImageMessage(uploadModel.url)
                    liveRoom.chatVM.sendImageMessageToUser(
                        model.getToUser(),
                        imageContent,
                        uploadModel.width,
                        uploadModel.height
                    )
                    imageMessageUploadingQueue.poll()
                    continueUploadQueue()
                } catch (e: Exception) {
                    model.status = UploadingImageModel.STATUS_UPLOAD_FAILED
                    e.printStackTrace()
                } finally {
                    notifyDataSetChange.postValue(Unit)
                }
            }
        })
    }

    fun getRecallStatus(message: IMessageModel): Int {
        if (liveRoom.currentUser.number == message.from.number) {
            return ChatMessageView.RECALL
        }
        return if (liveRoom.currentUser.type == LPConstants.LPUserType.Assistant || liveRoom.currentUser.type == LPConstants.LPUserType.Teacher) {
            ChatMessageView.DELETE
        } else ChatMessageView.NONE
    }

    fun reCallMessage(message: IMessageModel) {
        liveRoom.chatVM.requestMsgRevoke(message.id, message.from.userId)
    }

    fun reportMessage(context: Context, reportReason: MutableList<String>, message: IMessageModel) {
        compositeDisposable.add(liveRoom.chatVM.reportMessage(reportReason, message)
            .subscribe({
                ToastUtil(context).setText(context.getString(R.string.bjy_base_submit_success)).create().show()
            }) {
                ToastUtil(context).setText(context.getString(R.string.bjy_base_submit_fail)).create().show()
                it.printStackTrace()
            })
    }

    fun stickyMessage(messages: List<IMessageModel>) {
        liveRoom.chatVM.requestMsgStickyList(messages)
    }

    fun getExpressions(): List<LPExpressionModel> {
        val result = ArrayList<LPExpressionModel>()
        if (liveRoom.chatVM.expressions != null) {
            for (model in liveRoom.chatVM.expressions) {
                if (model is LPExpressionModel) {
                    result.add(model)
                }
            }
        }
        return result
    }

    /**
     * 从所有消息过滤出老师/助教的消息
     *
     * @param allMessages 所有消息
     * @return
     */
    private fun getFilterMessageList(allMessages: List<IMessageModel>?): List<IMessageModel> {
        val messageModelList = ArrayList<IMessageModel>()
        if (allMessages == null) {
            return messageModelList
        }
        val size = allMessages.size
        for (i in 0 until size) {
            val iMessageModel = allMessages[i]
            if (iMessageModel.from.type == LPConstants.LPUserType.Teacher
                || iMessageModel.from.type == LPConstants.LPUserType.Assistant
            ) {
                messageModelList.add(iMessageModel)
            }
        }
        return messageModelList
    }

    fun getTranslateResult(position: Int): String {
        val iMessageModel = getMessage(position)
        val lpMessageTranslateModel =
            translateMessageModels[iMessageModel.from?.userId + iMessageModel.time?.time]
        return if (lpMessageTranslateModel != null) {
            if (lpMessageTranslateModel.code == 0) {
                lpMessageTranslateModel.result
            } else {
                if (Locale.getDefault().country.equals(
                        "cn",
                        ignoreCase = true
                    )
                ) "翻译失败" else "Translate Fail!"
            }
        } else {
            ""
        }
    }

    fun translateMessage(
        message: String,
        messageId: String,
        fromLanguage: String,
        toLanguage: String
    ) {
        routerViewModel.liveRoom.chatVM.sendTranslateMessage(
            message,
            messageId,
            routerViewModel.liveRoom.roomId.toString(),
            routerViewModel.liveRoom.currentUser.userId,
            fromLanguage,
            toLanguage
        )
    }

    fun removeTranslateResult(message: IMessageModel) {
        translateMessageModels.remove(message.from?.userId + message.time?.time)
    }

    fun loadMoreWhisperList() {
        routerViewModel.privateChatUser.value?.let {
            val hasMore = privateChatMessagePageHasMoreMap[it.number] ?: true
            if (!hasMore) {
                notifyLoadDataComplete.value = Unit
                return
            }
            var page = privateChatMessagePageMap[it.number]
            if (page == null) {
                page = 0
            }
            privateChatMessagePageMap[it.number] = page
            liveRoom.chatVM.requestWhisperList(it.number, page)
        }
    }

    /**
     * 首次点击私聊加载，其余情况均手动加载
     */
    fun loadFirstWhisperList() {
        routerViewModel.privateChatUser.value?.let {
            var page = privateChatMessagePageMap[it.number]
            if (page == null) {
                page = 0
            } else {
                return
            }
            privateChatMessagePageMap[it.number] = page
            liveRoom.chatVM.requestWhisperList(it.number, page)
        }
    }

    override fun onCleared() {
        super.onCleared()
        translateMessageModels.clear()
        privateChatMessageFilterList.clear()
        privateChatMessagePool.clear()
        chatMessageFilterList.clear()
        imageMessageUploadingQueue.clear()
    }
}